#include "Avalon/ServiceLocator/Directory.hpp"
#include "Avalon/Base/Algorithm.hpp"
#include "Avalon/Serialization/DataShuttle.hpp"

using namespace Avalon;
using namespace Avalon::Serialization;
using namespace Avalon::ServiceLocator;
using namespace boost;
using namespace boost::signals2;
using namespace std;

AVALON_SERIALIZABLE(Directory, "Avalon.ServiceLocator.Directory", 0);

const Directory::Permission Directory::Permission::READ(
  Permission::DeclareNewIdentifier());
const Directory::Permission Directory::Permission::WRITE(
  Permission::DeclareNewIdentifier());
const Directory::Permission Directory::Permission::READ_WRITE(
  Permission::READ | Permission::WRITE);

Directory::Directory(const Tag& tag)
    : m_tag(tag) {}

Directory::Directory(const Tag& tag, const vector<Tag>& entries,
    const map<unsigned int, Permission>& permissions)
    : m_tag(tag),
      m_entries(entries),
      m_permissions(permissions) {}

Directory::~Directory() {}

DirectoryEntry::Type Directory::GetType() {
  return Type::DIRECTORY;
}

DirectoryEntry::Tag Directory::GetTag() {
  boost::lock_guard<boost::mutex> lock(m_mutex);
  return m_tag;
}

vector<DirectoryEntry::Tag> Directory::GetEntries() {
  boost::lock_guard<boost::mutex> lock(m_mutex);
  return m_entries;
}

map<unsigned int, Directory::Permission> Directory::GetPermissions() {
  boost::lock_guard<boost::mutex> lock(m_mutex);
  return m_permissions;
}

connection Directory::ConnectEntryChangedSignal(
    const EntryChangedSignal::slot_type& slot) {
  boost::lock_guard<boost::mutex> lock(m_mutex);
  for(vector<Tag>::const_iterator i = m_entries.begin();
      i != m_entries.end(); ++i) {
    slot(*i, true);
  }
  return m_entryChangedSignal.connect(slot);
}

connection Directory::ConnectEntryChangedSignal(
    const EntryChangedSignal::slot_type& slot, vector<Tag>* entries) {
  boost::lock_guard<boost::mutex> lock(m_mutex);
  *entries = m_entries;
  return m_entryChangedSignal.connect(slot);
}

void Directory::Shuttle(DataShuttle* shuttle, unsigned int version) {
  boost::lock_guard<boost::mutex> lock(m_mutex);
  shuttle->Shuttle("tag", m_tag);
  shuttle->Shuttle("entries", m_entries);
  shuttle->Shuttle("permissions", m_permissions);
}

Directory::Directory() {}

void Directory::AddEntry(const Tag& entry) {
  boost::lock_guard<boost::mutex> lock(m_mutex);
  m_entries.push_back(entry);
  m_entryChangedSignal(entry, true);
}

void Directory::RemoveEntry(const Tag& entry) {
  boost::lock_guard<boost::mutex> lock(m_mutex);
  Remove(m_entries, entry);
  m_entryChangedSignal(entry, false);
}
